home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 351-375 / 351 / pdc / pdcsrc.lzh / PDC / PeepGen.c < prev    next >
C/C++ Source or Header  |  1990-04-06  |  15KB  |  629 lines

  1.  
  2. /* PDC Compiler - A Freely Distributable C Compiler for the Amiga
  3.  *                Based upon prior work by Matthew Brandt and Jeff Lydiatt.
  4.  *
  5.  * PDC Compiler release 3.3 Copyright (C) 1989 Paul Petersen and Lionel Hummel.
  6.  * PDC Software Distribution (C) 1989 Lionel Hummel and Paul Petersen.
  7.  *
  8.  * This code is freely redistributable upon the conditions that this 
  9.  * notice remains intact and that modified versions of this file not be 
  10.  * distributed as part of the PDC Software Distribution without the express
  11.  * consent of the copyright holders.
  12.  *
  13.  *------------------------------------------------------------------
  14.  *
  15.  * $Log:    PeepGen.c,v $
  16.  * Revision 3.33  90/04/05  22:43:45  lionel
  17.  * Added code to rip out superfluous sign extensions after a moveq subst.
  18.  * 
  19.  * Revision 3.32  90/02/03  16:25:14  lionel
  20.  * None
  21.  * 
  22.  *------------------------------------------------------------------
  23.  */
  24.  
  25. /*
  26.  * PeepGen.c
  27.  * 
  28.  * Improves code generation using peephole optimization.
  29.  */
  30.  
  31. #include    <stdio.h>
  32. #include    "C.h"
  33. #include    "Expr.h"
  34. #include    "Gen.h"
  35. #include    "Cglbdec.h"
  36.  
  37. void   opt3();
  38. extern char    *xalloc();
  39.  
  40. struct ocode   *peep_head = NULL, *peep_tail = NULL;
  41.  
  42. struct amode   *
  43. copy_addr(ap)
  44.  
  45. /*
  46.  * copy an address mode structure (these things dont last).
  47.  */
  48.     struct amode   *ap;
  49. {
  50.     struct amode   *newap;
  51.  
  52.     if (ap == NULL)
  53.         return NULL;
  54.     newap = (struct amode *) xalloc(sizeof(struct amode));
  55.     newap->mode = ap->mode;
  56.     newap->preg = ap->preg;
  57.     newap->sreg = ap->sreg;
  58.     newap->tempflag = ap->tempflag;
  59.     newap->deep = ap->deep;
  60.     newap->offset = ap->offset;
  61.     return newap;
  62. }
  63.  
  64. void
  65. add_peep(new)
  66.  
  67. /*
  68.  * add the ocoderuction pointed to by new to the peep list.
  69.  */
  70.     struct ocode   *new;
  71. {
  72.     if (peep_head == NULL) {
  73.         peep_head = peep_tail = new;
  74.         new->fwd = NULL;
  75.         new->back = NULL;
  76.     }
  77.     else {
  78.         new->fwd = NULL;
  79.         new->back = peep_tail;
  80.         peep_tail->fwd = new;
  81.         peep_tail = new;
  82.     }
  83. }
  84.  
  85. void
  86. gen_code(op, len, ap1, ap2)
  87.  
  88. /*
  89.  * generate a code sequence into the peep list.
  90.  */
  91.     enum e_op       op;
  92.     int             len;
  93.     struct amode   *ap1, *ap2;
  94. {
  95.     struct ocode   *new;
  96.  
  97.     new = (struct ocode *) xalloc(sizeof(struct ocode));
  98.     new->opcode = op;
  99.     new->length = len;
  100.     new->oper1 = copy_addr(ap1);
  101.     new->oper2 = copy_addr(ap2);
  102.     add_peep(new);
  103. }
  104.  
  105. void
  106. gen_label(labno)
  107.  
  108. /*
  109.  * add a compiler generated label to the peep list.
  110.  */
  111.     int             labno;
  112. {
  113.     struct ocode   *new;
  114.  
  115.     new = (struct ocode *) xalloc(sizeof(struct ocode));
  116.     new->opcode = op_label;
  117.     new->oper1 = (struct amode *) labno;
  118.     add_peep(new);
  119. }
  120.  
  121. void
  122. put_ocode(p)
  123.  
  124. /*
  125.  * output the instruction passed.
  126.  */
  127.     struct ocode   *p;
  128. {
  129.     put_code(p->opcode, p->length, p->oper1, p->oper2);
  130. }
  131.  
  132. void
  133. flush_peep()
  134.  
  135. /*
  136.  * output all code and labels in the peep list.
  137.  */
  138. {
  139.     if (Options.Optimize)
  140.         opt3();     /* do the peephole optimizations */
  141.     while (peep_head != NULL) {
  142.         if (peep_head->opcode == op_label)
  143.             put_label((long) (peep_head->oper1));
  144.         else
  145.             put_ocode(peep_head);
  146.         peep_head = peep_head->fwd;
  147.     }
  148. }
  149.  
  150. void
  151. peep_move(ip)
  152.  
  153. /*
  154.  * peephole optimization for move instructions. makes quick immediates when
  155.  * possible. changes move #0,d to clr d. changes long moves to address
  156.  * registers to short when possible. changes move immediate to stack to pea.
  157.  */
  158.     struct ocode   *ip;
  159. {
  160.     struct ocode   *prev;
  161.     struct enode   *ep;
  162.  
  163.     if (ip->oper1->mode != am_immed) {
  164.         if (ip->oper1->mode == am_ainc) {   /* move (A7)+,xxxx  */
  165.             prev = ip->back;
  166.             while (prev != NULL && is_comment(prev->opcode))
  167.                 prev = prev->back;
  168.             if (prev != NULL) {
  169.                 if (prev->opcode == op_pea && ip->oper2->mode == am_areg) {
  170.                     if (ip->length == 4) {
  171.                         prev->opcode = op_lea;
  172.                         prev->oper2 = ip->oper2;
  173.                         prev->fwd = ip->fwd;
  174.                         if (ip->fwd != NULL)    /* Delete 2'nd  */
  175.                             ip->fwd->back = prev;
  176.                     }
  177.                 }
  178.                 if (prev->opcode == op_move && prev->length == ip->length) {
  179.                     if (prev->oper2->mode == am_adec) {
  180.                         if (ip->oper1->preg == prev->oper2->preg) {
  181.                             prev->oper2 = ip->oper2;
  182.                             prev->fwd = ip->fwd;
  183.                             if (ip->fwd != NULL)    /* Delete 2'nd  */
  184.                                 ip->fwd->back = prev;
  185.                         }
  186.                     }
  187.                 }
  188.             }
  189.             return;
  190.         }
  191.  
  192.         if (ip->oper1->mode != am_dreg && ip->oper1->mode != am_areg)
  193.             return;
  194.         if (ip->oper2->mode != am_dreg && ip->oper2->mode != am_areg)
  195.             return;
  196.  
  197.         prev = ip->back;
  198.         while (prev != NULL && is_comment(prev->opcode))
  199.             prev = prev->back;
  200.  
  201.         if (prev == NULL || prev->opcode != op_move)
  202.             return;
  203.  
  204.         if ( ip->length == prev->length &&
  205.             equal_address(ip->oper1, prev->oper1) &&    /* move.l A0,D0 */
  206.             equal_address(ip->oper2, prev->oper2)) {    /* move.l A0,D0 */
  207.             prev->fwd = ip->fwd;
  208.             if (ip->fwd != NULL)    /* Delete 2'nd  */
  209.                 ip->fwd->back = prev;
  210.             return;
  211.         }
  212.         if ( ip->length == prev->length &&
  213.             equal_address(ip->oper1, prev->oper2) &&    /* move.l A0,D0 */
  214.             equal_address(ip->oper2, prev->oper1)) {    /* move.l D0,A0 */
  215.             if (ip->oper1->mode == ip->oper2->mode ||
  216.                 prev->oper2->mode == am_dreg) {
  217.                 prev->fwd = ip->fwd;
  218.                 if (ip->fwd != NULL)    /* Delete 2'nd  */
  219.                     ip->fwd->back = prev;
  220.                 return;
  221.             }
  222.         }
  223.         return;
  224.     }
  225.  
  226.     ep = ip->oper1->offset;
  227.  
  228.     if (ep->nodetype != en_icon) {
  229.         if (ip->oper2->mode == am_areg) {
  230.             ip->opcode = op_lea;
  231.             ip->length = 0;
  232.             ip->oper1->mode = am_direct;
  233.         }
  234.         if (ip->oper2->mode == am_adec && (int) ip->oper2->preg == 7) {
  235.             ip->opcode = op_pea;
  236.             ip->length = 0;
  237.             ip->oper1->mode = am_direct;
  238.             ip->oper2 = NULL;
  239.         }
  240.         return;
  241.     }
  242.     if (ip->oper2->mode == am_areg) {
  243.         if (-32767 < ep->v.i && ep->v.i <= 32767)
  244.             ip->length = 2;
  245.     }
  246.     else if (ip->oper2->mode == am_dreg) {
  247.         if (-128 <= ep->v.i && ep->v.i <= 127) {
  248.             ip->opcode = op_moveq;
  249.             ip->length = 0;
  250.             while (ip->fwd && ip->fwd->opcode == op_ext) {
  251.                 ip->fwd = ip->fwd->fwd;
  252.                 if (ip->fwd != NULL) {
  253.                     ip->fwd->back = ip;
  254.                 }
  255.             }
  256.         }
  257.     }
  258.     else {
  259.         if (ep->v.i == 0) {
  260.             ip->opcode = op_clr;
  261.             ip->oper1 = ip->oper2;
  262.             ip->oper2 = NULL;
  263.         }
  264.         else if (ip->oper2->mode == am_adec && (int) (ip->oper2)->preg == 7) {
  265.             ip->opcode = op_pea;
  266.             ip->length = 0;
  267.             ip->oper1->mode = am_direct;
  268.             ip->oper2 = NULL;
  269.         }
  270.     }
  271. }
  272.  
  273. int
  274. equal_address(ap1, ap2)
  275.  
  276. /*
  277.  * compare two address nodes and return true if they are equivalent.
  278.  */
  279.     struct amode   *ap1, *ap2;
  280. {
  281.     if (ap1 == NULL || ap2 == NULL || ap1->mode != ap2->mode)
  282.         return FALSE;
  283.  
  284.     switch (ap1->mode) {
  285.     case am_freg:
  286.         return TRUE;
  287.     case am_areg:
  288.     case am_dreg:
  289.     case am_ainc:
  290.     case am_adec:
  291.         return ap1->preg == ap2->preg;
  292.     case am_indx:
  293.         return (ap1->preg == ap2->preg) &&
  294.             equalnode(ap1->offset, ap2->offset);
  295.     case am_indx2:
  296.     case am_indx3:
  297.         return (ap1->preg == ap2->preg) &&
  298.             (ap1->sreg == ap2->sreg);
  299.     }
  300.     return FALSE;
  301. }
  302.  
  303. void
  304. peep_asl(ip)
  305.  
  306. /*
  307.  * peephole optimization for add instructions. makes quick immediates out of
  308.  * small constants.
  309.  */
  310.     struct ocode   *ip;
  311. {
  312.     struct enode   *ep;
  313.  
  314.     if (ip->oper1->mode != am_immed)
  315.         return;
  316.  
  317.     ep = ip->oper1->offset;
  318.  
  319.     if (ep->nodetype != en_icon)
  320.         return;
  321.  
  322.     if (ip->oper2->mode != am_areg && ip->oper2->mode != am_dreg)
  323.         return;
  324.  
  325.     if (ep->v.i == 1) {
  326.         ip->opcode = op_add;
  327.         ip->oper1 = ip->oper2;
  328.     }
  329. }
  330.  
  331. void
  332. peep_add(ip)
  333.  
  334. /*
  335.  * peephole optimization for add instructions. makes quick immediates out of
  336.  * small constants.
  337.  */
  338.     struct ocode   *ip;
  339. {
  340.     struct enode   *ep;
  341.  
  342.     if (ip->oper1->mode != am_immed)
  343.         return;
  344.     ep = ip->oper1->offset;
  345.     if (ip->oper2->mode != am_areg)
  346.         ip->opcode = op_addi;
  347.     else {
  348.         if (isshort(ep))
  349.             ip->length = 2;
  350.     }
  351.     if (ep->nodetype != en_icon)
  352.         return;
  353.     if (1 <= ep->v.i && ep->v.i <= 8)
  354.         ip->opcode = op_addq;
  355.     else if (-8 <= ep->v.i && ep->v.i <= -1) {
  356.         ip->opcode = op_subq;
  357.         ep->v.i = -ep->v.i;
  358.     }
  359. }
  360.  
  361. void
  362. peep_sub(ip)
  363.  
  364. /*
  365.  * peephole optimization for subtract instructions. makes quick immediates
  366.  * out of small constants.
  367.  */
  368.     struct ocode   *ip;
  369. {
  370.     struct enode   *ep;
  371.  
  372.     if (ip->oper1->mode != am_immed)
  373.         return;
  374.     ep = ip->oper1->offset;
  375.     if (ip->oper2->mode != am_areg)
  376.         ip->opcode = op_subi;
  377.     else {
  378.         if (isshort(ep))
  379.             ip->length = 2;
  380.     }
  381.     if (ep->nodetype != en_icon)
  382.         return;
  383.     if (1 <= ep->v.i && ep->v.i <= 8)
  384.         ip->opcode = op_subq;
  385.     else if (-8 <= ep->v.i && ep->v.i <= -1) {
  386.         ip->opcode = op_addq;
  387.         ep->v.i = -ep->v.i;
  388.     }
  389. }
  390.  
  391. int
  392. is_comment(op)
  393.     enum e_op       op;
  394. {
  395.     return (op == op_comment || op == op_stabn || op == op_stabs);
  396. }
  397.  
  398. void
  399. peep_tst(ip)
  400.  
  401. /*
  402.  * peephole optimization for test instructions. if previous instruction
  403.  * should have set the condition codes properly delete. return value is true
  404.  * if instruction was deleted.
  405.  */
  406.     struct ocode   *ip;
  407. {
  408.     struct ocode   *prev;
  409.  
  410.     if (ip->oper1->mode == am_areg) 
  411.         return;
  412.  
  413.     prev = ip;
  414.     do {
  415.         prev = prev->back;
  416.         if (prev == NULL)
  417.             return;
  418.     } while (is_comment(prev->opcode));
  419.  
  420.     if ((((prev->opcode == op_move || prev->opcode == op_moveq)
  421.           && equal_address(prev->oper1, ip->oper1))
  422.          && prev->oper2->mode != am_areg)
  423.         || ((prev->opcode == op_ext) && (prev->length == ip->length)
  424.         && equal_address(prev->oper1, ip->oper1))
  425.         || (prev->opcode != op_label
  426.         && equal_address(prev->oper2, ip->oper1))) {
  427.         prev->fwd = ip->fwd;
  428.         if (prev->fwd != NULL)
  429.             prev->fwd->back = prev;
  430.     }
  431. }
  432.  
  433. void
  434. peep_cmp(ip)
  435.  
  436. /*
  437.  * peephole optimization for compare instructions. changes compare #0 to tst
  438.  * and if previous instruction should have set the condition codes properly
  439.  * delete. return value is true if instruction was deleted.
  440.  */
  441.     struct ocode   *ip;
  442. {
  443.     struct enode   *ep;
  444.     int             side;
  445.  
  446.     if (ip->oper1->mode == am_immed) {
  447.         ep = ip->oper1->offset;
  448.         side = 1;
  449.     }
  450.     else if (ip->oper2->mode == am_immed) {
  451.         ep = ip->oper2->offset;
  452.         side = 2;
  453.     }
  454.     else
  455.         return;
  456.  
  457.     if (ip->oper2->mode == am_areg || ip->oper1->mode == am_areg) {
  458.         if (isshort(ep))
  459.             ip->length = 2;
  460.         return;
  461.     }
  462.  
  463.     ip->opcode = op_cmpi;
  464.  
  465.     if (ep->nodetype != en_icon || ep->v.i != 0)
  466.         return;
  467.  
  468.     if (side == 1)
  469.         ip->oper1 = ip->oper2;
  470.  
  471.     ip->oper2 = NULL;
  472.     ip->opcode = op_tst;
  473.  
  474.     peep_tst(ip);
  475. }
  476.  
  477. void
  478. peep_muldiv(ip, op)
  479.  
  480. /*
  481.  * changes multiplies and divides by convienient values to shift operations.
  482.  * op should be either op_asl or op_asr (for divide).
  483.  */
  484.     struct ocode   *ip;
  485.     enum e_op       op;
  486. {
  487.     int             shcnt;
  488.  
  489.     if (Options.MulDiv32 || ip->oper1->mode != am_immed)
  490.         return;
  491.  
  492.     if (ip->oper1->offset->nodetype != en_icon)
  493.         return;
  494.  
  495.     switch (shcnt = (int) (ip->oper1->offset->v.i)) {
  496.     case 2:
  497.         shcnt = 1;
  498.         break;
  499.     case 4:
  500.         shcnt = 2;
  501.         break;
  502.     case 8:
  503.         shcnt = 3;
  504.         break;
  505.     case 16:
  506.         shcnt = 4;
  507.         break;
  508.     case 32:
  509.         shcnt = 5;
  510.         break;
  511.     case 64:
  512.         shcnt = 6;
  513.         break;
  514.     case 128:
  515.         shcnt = 7;
  516.         break;
  517.     case 256:
  518.         shcnt = 8;
  519.         break;
  520.     case 512:
  521.         shcnt = 9;
  522.         break;
  523.     case 1024:
  524.         shcnt = 10;
  525.         break;
  526.     case 2048:
  527.         shcnt = 11;
  528.         break;
  529.     case 4096:
  530.         shcnt = 12;
  531.         break;
  532.     case 8192:
  533.         shcnt = 13;
  534.         break;
  535.     case 16384:
  536.         shcnt = 14;
  537.         break;
  538.     default:
  539.         return;
  540.     }
  541.     ip->oper1->offset->v.i = shcnt;
  542.     ip->opcode = op;
  543.     ip->length = 4;
  544. }
  545.  
  546. void
  547. peep_uctran(ip)
  548.  
  549. /*
  550.  * peephole optimization for unconditional transfers. deletes instructions
  551.  * which have no path. applies to bra, jmp, and rts instructions.
  552.  */
  553.     struct ocode   *ip;
  554. {
  555.     while (ip->fwd != NULL && ip->fwd->opcode != op_label) {
  556.         ip->fwd = ip->fwd->fwd;
  557.         if (ip->fwd != NULL)
  558.             ip->fwd->back = ip;
  559.     }
  560.  
  561.     if (ip->opcode != op_jmp && ip->opcode != op_bra)
  562.         return;
  563.  
  564.     if (ip->fwd == NULL || ip->fwd->opcode != op_label)
  565.         return;
  566.  
  567.     if (ip->oper1 == NULL || ip->oper1->mode != am_direct)
  568.         return;
  569.  
  570.     if (ip->oper1->offset == NULL || ip->oper1->offset->nodetype != en_labcon)
  571.         return;
  572.  
  573.     if ((int) ip->fwd->oper1 == ip->oper1->offset->v.i) {
  574.         ip->back->fwd = ip->fwd;
  575.         if (ip->fwd != NULL)
  576.             ip->fwd->back = ip->back;
  577.     }
  578. }
  579.  
  580. void
  581. opt3()
  582.  
  583. /*
  584.  * peephole optimizer. This routine calls the instruction specific
  585.  * optimization routines above for each instruction in the peep list.
  586.  */
  587. {
  588.     struct ocode   *ip;
  589.  
  590.     for (ip = peep_head; ip != NULL; ip = ip->fwd) {
  591.         switch (ip->opcode) {
  592.         case op_asl:
  593.             peep_asl(ip);
  594.             break;
  595.         case op_move:
  596.             peep_move(ip);
  597.             break;
  598.         case op_add:
  599.             peep_add(ip);
  600.             break;
  601.         case op_sub:
  602.             peep_sub(ip);
  603.             break;
  604.         case op_cmp:
  605.             peep_cmp(ip);
  606.             break;
  607.         case op_tst:
  608.             peep_tst(ip);
  609.             break;
  610.         case op_muls:
  611.             peep_muldiv(ip, op_asl);
  612.             break;
  613.         case op_divs:
  614.             peep_muldiv(ip, op_asr);
  615.             break;
  616.         case op_mulu:
  617.             peep_muldiv(ip, op_lsl);
  618.             break;
  619.         case op_divu:
  620.             peep_muldiv(ip, op_lsr);
  621.             break;
  622.         case op_bra:
  623.         case op_jmp:
  624.         case op_rts:
  625.             peep_uctran(ip);
  626.         }
  627.     }
  628. }
  629.